package com.glodon.paas.qto.resource;

import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.glodon.paas.exception.BaseErrorException;
import com.glodon.paas.exception.PaasServerExceptionFactory;
import com.glodon.paas.job.JobConstants;
import com.glodon.paas.job.model.TaskStatus;
import com.glodon.paas.job.util.JsonUtil;
import com.glodon.paas.qto.model.Job;
import com.glodon.paas.qto.model.Task;
import com.glodon.paas.qto.service.QtoService;
import com.glodon.paas.qto.util.SecurityUtils;

/**
 * 接收前端任务调度请求.
 * 
 * @author botao.liao
 * 
 */
@Component
@Path("/job")
public class JobResource {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    private final DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
    @Autowired
    private QtoService qtoService;

    /**
     * 接收前端请求，转发到job server中
     * 
     * @param function
     * @param body
     * 
     * @return
     * @throws IOException
     * @throws BaseErrorException
     */
    @POST
    @Path("/{job}")
    @Produces(MediaType.APPLICATION_JSON)
    public String create(@Context HttpServletRequest request, @PathParam("job") String jobName) throws IOException,
            BaseErrorException {
        ServletInputStream is = request.getInputStream();
        String body = IOUtils.toString(is);
        logger.info("incoming job:{}, body:{}", jobName, body);
        Map<String, String> result = new HashMap<String, String>();
        String userId = SecurityUtils.getOwnerId(request);
        Job job;
        try {
            job = conver2Job(body);
            is.close();
        } catch (Exception e) {
            throw PaasServerExceptionFactory.validateException("bad json string from client", e);
        }

        if (StringUtils.isEmpty(job.getInput())) {
            throw PaasServerExceptionFactory.validateException("bad json string from client,input is null", null);
        }

        if (StringUtils.isEmpty(job.getOutput())) {
            throw PaasServerExceptionFactory.validateException("bad json string from client,output is null", null);
        }

        if (StringUtils.isEmpty(job.getStories())) {
            throw PaasServerExceptionFactory.validateException("bad json string from client,stories is null", null);
        }
        job.setName(jobName);
        job.setUserId(userId);
        String jobId = qtoService.create(job);
        result.put(JobConstants.JOB_ID, jobId);
        return JsonUtil.mapToJson(result);
    }

    @SuppressWarnings("rawtypes")
    @GET
    @Path("/{jobId}")
    @Produces(MediaType.APPLICATION_JSON)
    public Map query(@Context HttpServletRequest request, @PathParam("jobId") String jobId) throws BaseErrorException {
        Job job = qtoService.getJob(jobId);
        Map jsonResult = convert2Json(job);
        logger.info("query job progress:{}", jsonResult);
        return jsonResult;
    }

    @SuppressWarnings("rawtypes")
    @GET
    @Path("/list")
    @Produces(MediaType.APPLICATION_JSON)
    public List<Map> list(@Context HttpServletRequest request, @QueryParam("from") String from,
            @QueryParam("to") String to) throws BaseErrorException {
        String ownerId = SecurityUtils.getOwnerId(request);
        Date fromTime = null;
        Date toTime = null;
        try {
            if (from != null) {
                fromTime = dateFormat.parse(from);
            }
            if (to != null) {
                toTime = dateFormat.parse(to);
            }
        } catch (ParseException e) {
            throw PaasServerExceptionFactory.validateException("not valid time format:yyyyMMddHHmmss", e);
        }
        List<Job> jobs = qtoService.findByUserId(ownerId, fromTime, toTime);
        List<Map> jobsList = new ArrayList<Map>(jobs.size());
        for (Job job : jobs) {
            Map jobMap = convert2Json(job);
            jobsList.add(jobMap);
        }
        return jobsList;
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private Map convert2Json(Job job) {
        Map result = new HashMap();
        result.put(JobConstants.JOB_ID, job.getId());
        result.put(JobConstants.JOB_START_TIME, dateFormat.format(job.getStartTime()));
        result.put(JobConstants.PROPERTY_TASK_FILE_NAME, job.getFilename());
        if (job.getEndTime() == null) {// 状态未知
            result.put(JobConstants.TASK_PROGRESS, "processing");
        } else {
            result.put(JobConstants.TASK_PROGRESS, JobConstants.JOB_COMPLETE);
            result.put(JobConstants.JOB_END_TIME, dateFormat.format(job.getEndTime()));
            result.put(JobConstants.OUTPUT, job.getOutput());
        }
        List<Task> tasks = qtoService.findChildTask(job.getId());
        List<Map> taskList = new ArrayList<Map>(tasks.size());
        for (Task task : tasks) {
            taskList.add(convert2Map(task));
        }
        result.put("tasks", taskList);
        return result;
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private Map convert2Map(Task task) {
        TaskStatus status = task.getStatus();
        Map jsonMap = new HashMap();
        jsonMap.put(JobConstants.STORIES, task.getStories());
        jsonMap.put(JobConstants.PROPERTY_TASK_START_TIME, dateFormat.format(task.getStartTime()));
        jsonMap.put(JobConstants.PROPERTY_TASK_STATUS, status.name());
        jsonMap.put(JobConstants.TASK_MESSAGE, task.getMessage());
        jsonMap.put(JobConstants.TASK_PROGRESS, task.getProgress());
        jsonMap.put(JobConstants.PROPERTY_TASK_TYPE, task.getFunction());
        if (task.getResponseTime() != null) {
            jsonMap.put(JobConstants.PROPERTY_TASK_RESPONSE_TIME, dateFormat.format(task.getResponseTime()));
        }
        return jsonMap;
    }

    private Job conver2Job(String json) throws Exception {
        @SuppressWarnings("rawtypes")
        Map map = JsonUtil.jsonToMap(json);
        Job job = new Job();
        job.setInput((String) map.get(JobConstants.INPUT));
        job.setStories(StringUtils.join((Collection<?>) map.get(JobConstants.STORIES), ","));
        job.setOutput((String) map.get(JobConstants.OUTPUT));
        job.setFilename((String) map.get(JobConstants.PROPERTY_TASK_FILE_NAME));
        return job;
    }

    public void setQtoService(QtoService qtoService) {
        this.qtoService = qtoService;
    }
}
